module cpu5(ibus,clk,daddrbus,databus,iaddrbus,reset);
input[31:0] ibus;
input clk,reset;
output[31:0]daddrbus,iaddrbus;
inout[31:0] databus;

wire [31:0] pipedibus,asel,bsel,dsel,signext,signextpiped,wirebbus,dsel2,dsel3,Dselect,mux0,mux1,
				IDEX_dsel_out,EXMEM_dsel_out,mem_dbus,abus,bbus,dbus,IDEX_boperand,sw_bbus,pcmux_out,iaddrbus_wire;
wire imm,cint, Cin, imm2,imm3,Imm_mem,IDEX_imm_out,memtoreg,memtoreg2,IDEX_memtoreg_out,memtoreg3,EXMEM_memtoreg_out,
		memread,memread2,IDEX_memread_out,memread3,EXMEM_memread_out,eqdetout,Cout;
wire[3:0] sint, S;
wire [4:0] shamt;
wire [31:0] out_d;
reg [31:0] dsel_sw_check;

wire [31:0] pcincrementer1_out, pcextend_out,pcmux_next, pcmux_next_final;

alu32 pcincrementer1(
	.a(4),
	.b(iaddrbus),
	.out_d(pcincrementer1_out),
	.Cin(1'b0),
	.Cout(),
	.V(),
	.S(4'b0010),
	.shamt()
	);

assign iaddrbus = iaddrbus_wire;



piperegPC PC(
	.clk(clk),
	.in(pcmux_out),
	.out(iaddrbus_wire),
	.reset(reset)
	);
//assign iaddrbus = iaddrbus_wire;


wire [31:0] IFID_pcincrementer1_out;

piperegIFID IFID(
	.clk(clk),
	.in(ibus),
	.out(pipedibus),
	.in2(pcincrementer1_out),
	.out2(IFID_pcincrementer1_out),
	.reset(reset)
	);
wire beq,bne,pcjump,pcjumpR;		

wire [31:0] signext_left_shifted;

assign signext_left_shifted = (signext * 4);

wire [31:0] pcincrementer2_out;

assign pcextend_out = {IFID_pcincrementer1_out[31:28], pipedibus[25:0], 2'b00};

assign shamt =  pipedibus[10:6];


alu32 pcincrementer2(
	.a(signext_left_shifted),
	.b(IFID_pcincrementer1_out),
	.out_d(pcincrementer2_out),
	.Cin(1'b0),
	.Cout(),
	.V(),
	.S(4'b0010),
	.shamt()
	);
	
assign beq = (pipedibus[31:26] == 6'b110000) ? 1'b1 : 1'b0;
assign bne = (pipedibus[31:26] == 6'b110001) ? 1'b1 : 1'b0;
//assign pcjump = (pipedibus[31:26] == 6'b000101) ? 1'b1 : 1'b0;
assign pcjumpR =(pipedibus[5:0] == 6'b101100) ? 1'b1 : 1'b0;
assign pcmuxctrl = reset ? 1'b0 : ( ((beq & eqdetout) || (bne & ~eqdetout)) ? 1'b1 : 1'b0 );


assign pcjump = pcjumpR? 1'b1 : ((pipedibus[31:26] == 6'b000101)? 1'b1 : 1'b0);


mux2X1 pc_jumpR(
.in1(abus),
.in2(pcextend_out),
.out(pcmux_next_final),
.sel(pcjumpR)
);
mux2X1 pc_jump(
	.in1(pcmux_next_final),
	.in2(pcmux_next),
	.out(pcmux_out),
	.sel(pcjump)
	);
mux2X1 pcmux(
.in1(pcincrementer2_out),
.in2(pcincrementer1_out),
.out(pcmux_next),
.sel(pcmuxctrl)
);






wire slt,sle;
controller controllercpu4(
	.ibus(pipedibus),
	.clk(clk),
	.Aselect(asel),
	.Bselect(bsel),
	.dselect(dsel),
	.imm(imm),
	.cint(cint),
	.sint(sint),
	.memtoreg(memtoreg),
	.memread(memread),
	.slt(slt),
	.sle(sle)
	
	);
	
always @ (pipedibus or dsel)
begin
if (	( pipedibus[31:26] == 6'b011111) || ( pipedibus[31:26] == 6'b110000) || ( pipedibus[31:26] == 6'b110001)	)
dsel_sw_check = 32'b0;
else
dsel_sw_check = dsel;
end

	
//wire eqdetout,Cout;
regalu regalucpu4(
	.Aselect(asel),
	.Bselect(bsel),
	.Dselect(Dselect),
	.abus(abus),
	.bbus(bbus),
	.dbus(dbus),
	.clk(clk),
	.S(S),
	.shamt(shamt),
	.Cin(Cin),
	.signext(signextpiped),
	.imm(imm2),
	.mem_dbus(mem_dbus),
	.eq_det_out(eqdetout),
	.Cout(Cout)
	);
	
wire eqdet,slt2,sle2,IDEX_eq_det_out,IDEX_slt,IDEX_sle;
piperegIDEX IDEX(
	.clk(clk),
	.in1(dsel_sw_check),
	.in2(sint),
	.in3(cint),
	.in4(imm),
	.in5(signext),
	.in6(memtoreg),
	.in7(bbus),
	.in8(memread),
	.in9(eqdetout),
	.in10(slt),
	.in11(sle),
	.out1(dsel2),
	.out2(S),
	.out3(Cin),
	.out4(imm2),
	.out5(signextpiped),
	.out6(memtoreg2),
	.out7(sw_bbus),
	.out8(memread2),
	.out9(eqdet),
	.out10(slt2),
	.out11(sle2)
	);
	
assign IDEX_boperand = sw_bbus;	
assign IDEX_dsel_out = dsel2;
assign IDEX_memtoreg_out = memtoreg2;
assign IDEX_memread_out = memread2;
assign IDEX_eq_det_out = eqdet;
assign IDEX_slt = slt2;
assign IDEX_sle = sle2;

signext signextender(
	.in(pipedibus[15:0]),
	.out(signext)
	);
	
wire EXMEM_eqdet, EXMEM_slt,EXMEM_sle, EXMEM_Cout;
piperegEXMEM EXMEM(
	.clk(clk),
	.in1(IDEX_boperand),
	.in2(IDEX_memtoreg_out),
	.in3(IDEX_dsel_out),
	.in4(IDEX_memread_out),
	.in5(IDEX_eq_det_out),
	.in6(IDEX_slt),
	.in7(Cout),
	.in8(IDEX_sle),
	.out1(wirebbus),
	.out2(memtoreg3),
	.out3(dsel3),
	.out4(memread3),
	.out5(EXMEM_eqdet),
	.out6(EXMEM_slt),
	.out7(EXMEM_Cout),
	.out8(EXMEM_sle)
	);

assign daddrbus = dbus;

/*always @ ( EXMEM_memread_out or EXMEM_memtoreg_out or EXMEM_set_ctrl or EXMEM_Cout or EXMEM_eqdet or wirebbus)
begin
	if( (EXMEM_memread_out & ~EXMEM_memtoreg_out) || (~EXMEM_memread_out & ~EXMEM_memtoreg_out) )
		databus_out = 32'bz;
	else if( (EXMEM_set_ctrl == 1) & ( (~EXMEM_Cout & ~EXMEM_eqdet) || (~EXMEM_Cout | EXMEM_eqdet) ) )
		databus_out = 1;
	else
		databus_out = wirebbus;
end*/

assign databus = 
			( (EXMEM_memread_out & ~EXMEM_memtoreg_out) || (~EXMEM_memread_out & ~EXMEM_memtoreg_out) ) ? 32'bz : 
			(( (( (EXMEM_slt == 1) &  (~EXMEM_Cout & ~EXMEM_eqdet) )) || ((EXMEM_sle == 1) & (~EXMEM_Cout | EXMEM_eqdet) ) ) ? 32'b1 : wirebbus);
				


//assign databus = ((EXMEM_memread_out & ~EXMEM_memtoreg_out) || (~EXMEM_memread_out & ~EXMEM_memtoreg_out))? 32'bz : wirebbus;
assign EXMEM_dsel_out = dsel3;
assign EXMEM_memtoreg_out = memtoreg3;	
assign EXMEM_memread_out = memread3;

piperegMEMWB MEMWB(
	.clk(clk),
	.in1(databus),
	.in2(daddrbus),
	.in3(EXMEM_memread_out),
	.in4(EXMEM_dsel_out),
	.out1(mux0),
	.out2(mux1),
	.out3(Imm_mem),
	.out4(Dselect)
	);
	
mux2X1 memtoreg_mux(
	.in1(mux0),
	.in2(mux1),
	.out(mem_dbus),
	.sel(Imm_mem)
	);
	


endmodule
